# -*- coding: utf-8 -*-
#描述了棋盘的相关环境
import random
import Config
import turtle

class PlayBoard():

    def __init__(self):

        #给出随机障碍
        def getRandomBarrier(play1base,play2base):
            barrier_states = set()
            #给出指定的障碍
            while(True):
                #不能在大本营
                barrier_location = random.randint(0, Config.CHECKERBOARDSIZE * Config.CHECKERBOARDSIZE)
                if barrier_location == play1base or barrier_location == play2base:
                    continue

                barrier_states.add(barrier_location)
                if len(barrier_states) == Config.BARRIERNUM:
                    break

            return barrier_states

        #给出随机的奖励
        def getRandomReward(barrier_states,play1base,play2base):
            reward_states = {}
            #给出指定的障碍
            while(True):
                randomReward =  (random.randint(0, Config.CHECKERBOARDSIZE * Config.CHECKERBOARDSIZE))
                if randomReward in barrier_states or randomReward == play1base or randomReward == play2base:
                    continue

                #给出随机价格
                reward_states[randomReward] = random.randint(Config.LOWREWARDPRICE, Config.HIGHREWARDPRICE)
                if len(reward_states) == Config.REWARDNUM:
                    break

            return reward_states




        #给出随机的棋盘
        #设置大本营
        self.play1base = 5 * Config.CHECKERBOARDSIZE + 5
        self.play2base = 6 * Config.CHECKERBOARDSIZE + 6

        self.barrier_states = getRandomBarrier(self.play1base,self.play2base)
        self.reward_states  = getRandomReward(self.barrier_states,self.play1base,self.play2base)
        self.init_reward_states = self.reward_states.copy()


        self.state1,self.state2 = self.play1base,self.play2base
        #初始化分数
        self.play1score = 0
        self.play2score = 0
        self.play1capacity = 0
        self.play2capacity = 0
        self.final1Score = 0
        self.final2Score = 0
        self.play1WinCount = 0
        self.play2WinCount = 0
        self.runNum = 0
        self.numActionDic = {0:"U",1:"D",2:"L",3:"R"}

    # 给出随机初始位置
    def getInitState(self):
        # 给出指定的障碍
        while (True):
            Player1 = random.randint(0, Config.CHECKERBOARDSIZE * Config.CHECKERBOARDSIZE)
            if Player1 not in self.barrier_states:
                break
        while (True):
            Player2 = random.randint(0, Config.CHECKERBOARDSIZE * Config.CHECKERBOARDSIZE)
            if Player2 not in self.barrier_states and Player2 != Player1:
                break
        return Player1, Player2

    def reSet(self):

        self.reward_states = self.init_reward_states.copy()
        self.state1, self.state2 = 5 * Config.CHECKERBOARDSIZE + 5,6 * Config.CHECKERBOARDSIZE + 6
        self.play1score = 0
        self.play2score = 0

        self.play1capacity = 0
        self.play2capacity = 0
        self.final1Score = 0
        self.final2Score = 0

        self.runNum = 0



    # 随机增加奖励，每回合在空白格随机增加
    def addRandomReward(self):
        reward_states = {}
        # 给出指定的障碍
        while (True):
            randomReward = (random.randint(0, Config.CHECKERBOARDSIZE * Config.CHECKERBOARDSIZE))
            if randomReward in self.barrier_states or randomReward in self.reward_states \
                    or randomReward == self.play1base or randomReward == self.play2base:
                continue

            # 给出随机价格
            self.reward_states[randomReward] = random.randint(Config.LOWREWARDPRICE, Config.HIGHREWARDPRICE)
            break

        return reward_states

    #给出前后左右之后棋盘的取值
    def getActionNum(self,state,action):
        if action == "U":
            result = state - Config.CHECKERBOARDSIZE
        if action == "D":
            result = state + Config.CHECKERBOARDSIZE
        if action == "L":
            result = state - 1
        if action == "R":
            result = state + 1
        if action == "S":
            result = state

        return result

    #判断在当前局面下，走步是否合法
    def judgeActionLegal(self,state,action,player):

        newState = self.getActionNum(state,action)

        #超过上下边界
        if newState < 0 or newState > Config.CHECKERBOARDSIZE * Config.CHECKERBOARDSIZE -1:
            return False

        if state % Config.CHECKERBOARDSIZE == 0 and action == "L":
            return False

        if state % Config.CHECKERBOARDSIZE == Config.CHECKERBOARDSIZE - 1 and action == "R":
            return False

        if newState in self.barrier_states:
            return False

        # 不能和敌方或者敌方大本营重合
        if player == 1:
            if newState == self.play2base:
                return  False
        if player == 2:
            if newState == self.play1base:
                return  False

        return True



    #每一轮的更新过程,每走一步会衰减reward
    def updateReward(self,next_state):

        rewardKeys = self.reward_states.keys()
        toDelKeys = []

        for key in rewardKeys:
            #如果拿到这个快件，则直接清除
            if key == next_state:
                toDelKeys.append(key)
                continue

            self.reward_states[key] = self.reward_states[key] - Config.GAMMA

            #如果等于0 ，价值为0的 也清除
            if self.reward_states[key] < 0:
                toDelKeys.append(key)

        for delkey in toDelKeys:
            self.reward_states.pop(delkey)
            self.addRandomReward()


    def move(self, player,action):

        # 强制要求合法，必须是合法的步子
        def assetLegal (state,action,player):
            if self.judgeActionLegal(state, action,player) == False:

                print("player " + str(player) + " move is illegal")
                print(state)
                print(action)
                print(self.barrier_states)
                assert self.judgeActionLegal(state, action,player)


        if player == 1:
            next_state = self.getActionNum(self.state1, action)
            assetLegal(self.state1,action,player)

        if player == 2:
            next_state = self.getActionNum(self.state2, action)
            assetLegal(self.state2, action,player)


        if next_state not in self.reward_states.keys():
            r = 0.0
        else:
            r = self.reward_states[next_state]


        is_terminal = False




        # 判断当前是否还有豆，如果没豆，则认为是退出,这个需要验证
        if len(self.reward_states.keys()) <= 0:
            is_terminal = True

        # 重置当前节点,给出相关分数
        if player == 1:
            self.state1 = next_state
            #没满载的时候
            if self.play1capacity < Config.CAPACITYLIMIT:
                self.play1score = self.play1score + r
                if r > 0:
                    self.play1capacity = self.play1capacity + 1

                self.updateReward(next_state)

            # 如果返回大本营  算最终得分
            if next_state == self.play1base:
                self.final1Score = self.final1Score + self.play1score
                self.play1score = 0
                self.play1capacity = 0

        if player == 2:
            self.state2 = next_state
            if self.play2capacity < Config.CAPACITYLIMIT:
                self.play2score = self.play2score + r
                if r > 0:
                    self.play2capacity = self.play2capacity + 1
                self.updateReward(next_state)

            # 判断回城
            if next_state == self.play2base:
                self.final2Score = self.final2Score + self.play2score
                self.play2score = 0
                self.play2capacity = 0


        self.runNum = self.runNum  + 1
        if self.runNum > Config.RUNNUMMBERLIMIT * 2:
            is_terminal = True

        #判断是否终局
        return is_terminal

    def terminal(self):
        if (self.final1Score > self.final2Score):
            self.play1WinCount = self.play1WinCount + 1
            print("player 1 win")


        if (self.final2Score > self.final1Score):
            self.play2WinCount = self.play2WinCount + 1
            print("player 2 win")

        print("player 1 win count is :"  + str(self.play1WinCount))
        print("player 2 win count is :"  + str(self.play2WinCount))

    def drawingboard(self):

        N = Config.CHECKERBOARDSIZE
        # boardSet = generateboard([0.35, 0.15, 0.5], N)
        # board = boardSet[0]

        # print(board.keys())

        n = 40  # 每行间隔
        x = -300  # x初始值
        y = -300  # x初始值
        turtle.tracer(False)
        t = turtle.Turtle(visible=False)
        tNum = turtle.Turtle(visible=False)
        tPlayer = turtle.Turtle(visible=False)
        # t.tracer(0)
        t.pensize(2)

        #左上转右下
        def returnState(i,j):
            return  (Config.CHECKERBOARDSIZE - j) * Config.CHECKERBOARDSIZE + i

        # 先画12*12的正方形，并按要求涂黑,其中的障碍点 要涂
        for i in range(N):
            for j in range(1, N + 1):
                t.penup()
                t.goto(x + i * n, y + j * n)
                t.pendown()
                # if board[(i + 1, j)][0] != 2:
                if returnState(i,j) not in self.barrier_states:
                    for index in range(4):
                        t.forward(n)
                        t.left(90)
                    t.penup()
                else:
                    t.begin_fill()
                    t.fillcolor('black')
                    for index in range(4):
                        t.forward(n)
                        t.left(90)
                    t.end_fill()
                t.penup()

        for i in range(N):
            for j in range(1, N + 1):
                #给出奖励分数
                nowState = returnState(i,j)

                if nowState in self.reward_states.keys():
                    tNum.penup()
                    tNum.goto(x + i * n + n / 3.0, y + j * n + n / 3.0)
                    tNum.pendown()
                    tNum.color('gold')
                    tNum.write(str(self.reward_states[nowState]), font=("Times", 14, "bold"))
                    tNum.color('black')
                    tNum.penup()
                    tNum.goto(x + i * n, y + j * n)

                #如果是棋子1
                if nowState == self.state1:
                    tPlayer.penup()
                    tPlayer.goto(x + i * n + n / 2.0, y + j * n + n / 3.5)
                    tPlayer.pendown()
                    tPlayer.begin_fill()
                    tPlayer.color('red')
                    tPlayer.circle(10)
                    tPlayer.end_fill()
                    tPlayer.color('black')
                    tPlayer.penup()

                #如果是棋子2
                if nowState == self.state2:
                    tPlayer.penup()
                    tPlayer.goto(x + i * n + n / 2.0, y + j * n + n / 3.5)
                    tPlayer.pendown()
                    tPlayer.begin_fill()
                    tPlayer.color('blue')
                    tPlayer.circle(10)
                    tPlayer.end_fill()
                    tPlayer.color('black')
                    tPlayer.penup()

        #画大本营
        t.penup()
        t.goto(x + 5*n + n/4, y + 7*n + n/3.5)
        t.pendown()
        t.color('red')
        t.write('仓库', font=("Times", 14, "bold"))
        t.penup

        t.penup()
        t.goto(x + 6 * n + n / 4, y + 6 * n + n / 3.5)
        t.pendown()
        t.color('blue')
        t.write('仓库', font=("Times", 14, "bold"))
        t.penup

        # t.color('black')
        #
        # # 再画外面一个正方形
        # t.penup
        # x1 = x - n * 0.12
        # y1 = y - n * 0.12 + n
        # t.goto(x1, y1)
        # t.pendown()
        # t.pensize(4)
        # for index in range(4):
        #     t.forward(n * N + 2 * n * 0.12)
        #     t.left(90)


        ##画分数版，给出分数
        #先画player1
        t.penup()
        x1 = x + (N + 1) * n
        y1 = y + (N / 2.0) * n + n * 0.2
        t.goto(x1, y1)
        t.pendown()
        t.begin_fill()
        t.color('red')
        t.circle(10)
        t.end_fill()
        t.pendown()
        tNum.penup()
        x1 = x + (N + 1) * n + 0.75 * n
        y1 = y + (N / 2.0) * n + n * 0.2
        tNum.goto(x1, y1)
        tNum.pendown()
        tNum.color('gold')
        tNum.write(str(self.play1score), font=("Times", 18, "bold"))
        tNum.color('black')
        tNum.penup()

        x1 = x + (N + 1) * n + 1.75 * n
        y1 = y + (N / 2.0) * n + n * 0.2
        tNum.goto(x1, y1)
        tNum.pendown()
        tNum.color('gold')
        tNum.write(str(self.play1capacity), font=("Times", 18, "bold"))
        tNum.color('black')
        tNum.penup()
        x1 = x + (N + 1) * n + 2.3 * n
        y1 = y + (N / 2.0) * n + n * 0.2
        tNum.goto(x1, y1)
        tNum.pendown()
        tNum.color('gold')
        tNum.write(str(self.final1Score), font=("Times", 18, "bold"))
        tNum.color('black')

        #再画player2分数
        t.penup()
        x1 = x + (N + 1) * n
        y1 = y + (N / 2.0) * n - n * 0.6
        t.goto(x1, y1)
        t.pendown()
        t.begin_fill()
        t.color('blue')
        t.circle(10)
        t.end_fill()

        tNum.penup()
        x1 = x + (N + 1) * n + 0.75 * n
        y1 = y + (N / 2.0) * n - n * 0.6
        tNum.goto(x1, y1)
        tNum.pendown()
        tNum.color('gold')
        tNum.write(str(self.play2score), font=("Times", 18, "bold"))
        tNum.color('black')

        tNum.penup()
        x1 = x + (N + 1) * n + 1.75 * n
        y1 = y + (N / 2.0) * n - n * 0.6
        tNum.goto(x1, y1)
        tNum.pendown()
        tNum.color('gold')
        tNum.write(str(self.play2capacity), font=("Times", 18, "bold"))
        tNum.color('black')

        tNum.penup()
        x1 = x + (N + 1) * n + 2.3 * n
        y1 = y + (N / 2.0) * n - n * 0.6
        tNum.goto(x1, y1)
        tNum.pendown()
        tNum.color('gold')
        tNum.write(str(self.final2Score), font=("Times", 18, "bold"))
        tNum.color('black')

        t.clear()
        tNum.clear()
        tPlayer.clear()

    #给出一个返回力彬棋盘的接口
    def retunnLiBinBoard(self):

        board = {}
        players = []
        scores = []

        # boardSet[0]: dictionary
        # boardSet[(i, j)] = (index, score)
        #
        # 表示棋盘每个位置的类型和分值
        # index = 1 包裹 score为分值
        # index = 2 阻碍 score为 0
        # index = 3 可走的地方 score为0
        # index = 4 player，score区分选手
        #
        # boardSet[1]: list
        # boardSet[1][0] = (i, j, 4, 1)
        # boardSet[1][1] = (i, j, 4, 1)
        # 表示player的位置
        #
        # boardSet[2]: list
        # 表示player的分数
        # boardSet[2][0] = (1, scoreNow, scoreOld)
        # boardSet[2][1] = (2, scoreNow, scoreOld)
        for location in range(0,Config.CHECKERBOARDSIZE * Config.CHECKERBOARDSIZE):

            #给出坐标的转换
            i = location % Config.CHECKERBOARDSIZE
            j = Config.CHECKERBOARDSIZE - int(location / Config.CHECKERBOARDSIZE)

            #如果是阻碍
            if location in self.barrier_states:
                board[(i, j)] = (2, 0)

            else:
                #赋值为通道
                board[(i, j)] = (3, 0)
                #如果是奖励
                if location in self.reward_states.keys():
                    board[(i, j)] = (1, self.reward_states[location])
                #如果是选手
                if location == self.state1:
                    board[(i, j)] = (4,0)
                    play1info = ([i, j, 4, 1])
                if location == self.state2:
                    board[(i, j)] = (4, 1)
                    play2info = ([i, j, 4, 2])

        players = [play1info,play2info]
        #返回分数，老分数暂时以0替代
        scores = [(1, self.play1score, 0),(2, self.play2score, 0)]
        return [board,players,scores]








